//
//  UIDevice+JW.swift
// @project：JWHelperKit
// @author：linjw(10126121@qq.com)
// @time: 2022/12/20
// Copyright © 2018年 Linjw. All rights reserved.
//

import UIKit
import WebKit
import CoreServices
#if canImport(UniformTypeIdentifiers)
import UniformTypeIdentifiers
#endif

public extension JWNamespaceWrapper where T: UIDevice {
    
    /// 是否 iPad
    static var isIPad: Bool { return UIDevice.isIPad }
    
    /// 是否 iPhone
    static var isIPhone: Bool { return UIDevice.isIPhone }
    
    /// 是否 模拟器
    static var isSimulator: Bool { return UIDevice.isSimulator }
    
    /// 系统版本号
    static var iosVersion: String { return UIDevice.iosVersionStr }
    
    /// app 版本号
    static var appVersion: String { return UIDevice.appVersionStr }
    
    /// app 编译号
    static var appBundleVersion: String { return UIDevice.appBundleStr }
    
    /// app 名
    static var appDisplayName: String { return UIDevice.appDisplayName }
    
    /// app BundleId
    static var appBundleId: String { return UIDevice.appBundleId }
    
    /// 是否 iPhoneX
    static var isIPhoneX: Bool { return UIDevice.isIPhoneX }
    
    /// 是否刘海屏
    static var isFringeScreen: Bool { return UIDevice.isFringeScreen }
    
    /// 主window
    static var keyWindow: UIWindow? { return UIDevice.keyWindow }
    /// windows
    static var windows: [UIWindow] { return UIDevice.windows }
    
    /// 屏幕对象
    static var screen: UIScreen { return UIDevice.screen }
    
    /// 屏幕亮度
    static var screenBrightness: Int { return UIDevice.screenBrightness }
    
    /// 屏幕位置
    static var screenCurrentBounds: CGRect { return UIDevice.screenCurrentBounds }
    
    /// 屏幕宽
    static var screenWidth: CGFloat { return UIDevice.screenWidth }
    
    /// 屏幕高
    static var screenHeight: CGFloat { return UIDevice.screenHeight }
    
    /// 横竖屏高度
    static var screenAutoHeight: CGFloat { return UIDevice.screenCurrentBounds.size.height }
    
    /// 横竖屏宽度
    static var screenAutoWidth: CGFloat { return UIDevice.screenCurrentBounds.size.width }
    
    ///  safeAreaInsets (必须在设置了keyWindow后，才能用)
    static var safeAreaInsets: UIEdgeInsets { return UIDevice.safeAreaInsets }
    
    ///  navigationBar高
    static var navBarHeight: CGFloat { return UIDevice.navBarHeight }
    
    /// tabbar 高
    static var tabBarHeight: CGFloat { return UIDevice.tabBarHeight }
    
    /// statusBar 高
    static var statusBarHeight: CGFloat { return UIDevice.statusBarHeight }
    
    /// 屏幕与 iPhone6 宽度比
    static var screenWidthScale: CGFloat { return UIDevice.screenWidthScale }
    
    /// 缓存目录
    static var cacheDir: String { return UIDevice.cacheDir }
    
    /// 临时文件目录
    static var tempDir: String { return UIDevice.tempDir }
    
    /// 文档目录
    static var documentDir: String { return UIDevice.documentDir }
    
    /// app icon 图片名
    static var appIconName: String? { return UIDevice.appIconName }
    
    // 是否横屏
    static var isLandscape: Bool { return UIApplication.shared.statusBarOrientation.isLandscape }
    
    /// 开关键盘 (必须在设置了keyWindow后，才能用)
    static func endEditing(_ force: Bool = true) { UIApplication.shared.keyWindow?.endEditing(force) }
    
    //    /// 根据后缀获取对应的Mime-Type
    //    /// 需要在Build Phases - Link Binary With Libraries - 导入UniformTypeIdentifiers，并设置为Optional，否则iOS14以下，会报错
    //    @discardableResult
    //    static func mimeType(pathExtension: String) -> String {
    //        if #available(iOS 14.0, *) {
    //            if let type = UTType(filenameExtension: pathExtension) {
    //                if let mimetype = type.preferredMIMEType {
    //                    return mimetype as String
    //                }
    //            }
    //        } else {
    //            if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as NSString, nil)?.takeRetainedValue() {
    //                if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
    //                    return mimetype as String
    //                }
    //            }
    //        }
    //        return "application/octet-stream" // 文件资源类型如果不知道，传万能类型application/octet-stream，服务器会自动解析文件类
    //    }
    
    /// 删除文件
    @discardableResult
    static func removeFile(atPath: String?) -> Bool {
        if let atPath = atPath, FileManager.default.fileExists(atPath: atPath) {
            do {
                try FileManager.default.removeItem(atPath: atPath)
            } catch {
                return false
            }
            return true
        }
        return false
    }
    
    /// 跳转到设置
    static func toSystemPrivacySettingsView() {
        guard let appSetting = URL(string: UIApplication.openSettingsURLString) else { return }
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(appSetting, options: [:], completionHandler: nil)
        } else {
            UIApplication.shared.openURL(appSetting)
        }
    }
    
    /// 拨打电话(注意：iOS10.2前，不会弹ActionSheet)
    static func callPhone(_ phone: String) {
        let phoneText = "tel://" + phone
        if let url = URL(string: phoneText), UIApplication.shared.canOpenURL(url) {
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:]) { _ in }
            } else {
                UIApplication.shared.openURL(url)
            }
        }
    }
    
    /// 屏幕方向转旋转角度
    static func transformRotationAngle(from io: UIInterfaceOrientation) -> CGAffineTransform {
        return UIDevice.wTransformRotationAngle(from: io)
    }
    
    /// 设备方向转屏幕方向
    static func interfaceOrientation(from deviceO: UIDeviceOrientation) -> UIInterfaceOrientation {
        return UIDevice.wInterfaceOrientation(from: deviceO)
    }
    
    /// 当前屏幕方向
    static var currentInterfaceOrientation: UIInterfaceOrientation { return UIDevice.currentInterfaceOrientation() }
    
    /// 转屏
    static func orientation(to: UIInterfaceOrientation) {
        
        if #available(iOS 16.0, *) {
            let currentScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
            let geometryPreferencesIOS = UIWindowScene.GeometryPreferences.iOS(interfaceOrientations: to.isLandscape ? .landscape : .portrait)
            currentScene?.requestGeometryUpdate(geometryPreferencesIOS, errorHandler: { error in
                debugPrint("强制横屏错误: \(error)")
            })
        } else {
//            这句，会导致16.0崩溃，iOS15.7测试会导致崩溃，故注释了
//            UIDevice.current.setValue(UIInterfaceOrientation.unknown.rawValue, forKey: "orientation")
            UIDevice.current.setValue(to.rawValue, forKey: "orientation")
        }
        
        UIViewController.attemptRotationToDeviceOrientation()
        
    }
    
    /// 加载xib, 如：Bundle.loadNib("ViewXibName", owner: self); self.addSubview(self.contentView)
    static func loadNib(_ name: String, owner: AnyObject!) {
        _ = Bundle.main.loadNibNamed(name, owner: owner, options: nil)?[0]
    }
    
    /// 加载xib, 如：let view: ViewXibName = Bundle.loadNib("ViewXibName")
    static func loadNib<T>(_ name: String) -> T? {
        return Bundle.main.loadNibNamed(name, owner: nil, options: nil)?[0] as? T
    }
    
    /// 延迟运行
    static func runThisAfterDelay(seconds: Double, queue: DispatchQueue, after: @escaping () -> Void) {
        let time = DispatchTime.now() + Double(Int64(seconds * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
        queue.asyncAfter(deadline: time, execute: after)
    }
    
    /// 在主线程中运行
    static func runThisInMainThread(_ block: @escaping () -> Void) {
        DispatchQueue.main.async(execute: block)
    }
    
    /// 在默认优先队列中运行
    static func runThisInBackground(_ block: @escaping () -> Void) {
        DispatchQueue.global(qos: .default).async(execute: block)
    }
    
    /// 保持屏幕活动(唤醒)状态
    static func keepTheScreenStatus(active: Bool = true) {
        DispatchQueue.main.async {
            UIApplication.shared.isIdleTimerDisabled = active
        }
    }
    
}

fileprivate extension UIDevice {
    
    static func currentInterfaceOrientation() -> UIInterfaceOrientation {
        guard #available(iOS 13, *) else { return UIApplication.shared.statusBarOrientation }
        return keyWindow?.windowScene?.interfaceOrientation ?? .unknown
    }
    
    static func wTransformRotationAngle(from io: UIInterfaceOrientation) -> CGAffineTransform {
        var t: CGAffineTransform = CGAffineTransform.identity
        if io == UIInterfaceOrientation.portrait {
            
        } else if io == UIInterfaceOrientation.landscapeLeft {
            t = CGAffineTransform(rotationAngle: CGFloat(-Double.pi / 2))
        } else if io == UIInterfaceOrientation.landscapeRight {
            t = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
        }
        return t
    }
    
    // 设备方向转化为屏幕方向
    static func wInterfaceOrientation(from deviceO: UIDeviceOrientation) -> UIInterfaceOrientation {
        
        switch deviceO {
        case .landscapeLeft:
            return .landscapeRight
        case .landscapeRight:
            return .landscapeLeft
        case .unknown:
            return .unknown
        case .portrait:
            return .portrait
        case .portraitUpsideDown:
            return .portraitUpsideDown
        default:
            return .portrait
            
        }
    }
    
    static let isIPad: Bool = (UIDevice.current.userInterfaceIdiom == .pad)
    
    static let isIPhone: Bool = (UIDevice.current.userInterfaceIdiom == .phone)
    
    static let isSimulator: Bool = {
        #if os(iOS) && targetEnvironment(simulator)
        return true
        #else
        return false
        #endif
    }()
    
    static var isIPhoneX: Bool {
        guard UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.phone else { return false }
        guard #available(iOS 11.0, *) else { return false }
        return (self.keyWindow?.safeAreaInsets.bottom ?? 0) > 0
    }
    
    static var windows: [UIWindow] {
        if #available(iOS 13, *) {
            let sceneList = UIApplication.shared.connectedScenes
            let useableSceneList = sceneList.filter { ($0 is UIWindowScene) }.compactMap { $0 as? UIWindowScene }
            let result = useableSceneList.flatMap { $0.windows }
            return result
        }
        return UIApplication.shared.windows
    }
    
    static var keyWindow: UIWindow? {
        if #available(iOS 13, *) {
            let sceneList = UIApplication.shared.connectedScenes
            let useableSceneList = sceneList.filter { ($0 is UIWindowScene) }.compactMap { $0 as? UIWindowScene }
            let keyWindow = useableSceneList.flatMap { $0.windows }.first { $0.isKeyWindow }
            return keyWindow
        }
        return UIApplication.shared.keyWindow
    }
    
    static var screen: UIScreen {
        guard #available(iOS 13, *) else { return UIScreen.main }
        return self.keyWindow?.windowScene?.screen ?? UIScreen.main
    }
        
    static var screenWidth: CGFloat { return CGFloat(screen.bounds.size.width) }
    
    static var screenHeight: CGFloat { return CGFloat(screen.bounds.size.height)  }
    
    static var statusBarHeight: CGFloat {
        if #available(iOS 13, *) {
            return (self.keyWindow?.windowScene?.statusBarManager?.statusBarFrame.maxY ?? 0)
        }
        return CGFloat(UIApplication.shared.statusBarFrame.maxY)
    }
    static var navBarHeight: CGFloat { return statusBarHeight + navBarIntrinsicHeight }
    static let tabBarHeight: CGFloat = tabBarIntrinsicHeight + UIDevice.safeAreaInsets.bottom
    static let navBarIntrinsicHeight: CGFloat = 44.0
    static let tabBarIntrinsicHeight: CGFloat = 49.0
    
    static let screenWidthScale: CGFloat = CGFloat(UIScreen.main.bounds.width / 375.0)
    
    static var screenCurrentBounds: CGRect {
        
        var rect = UIScreen.main.bounds
        
        if UIApplication.shared.statusBarOrientation.isLandscape {
            let buffer = rect.size.width
            rect.size.width = rect.size.height
            rect.size.height = buffer
        }
        return rect
        
    }
    
    static let safeAreaInsets: UIEdgeInsets = {
        let defaultInsets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0)
        guard #available(iOS 11.0, *) else { return defaultInsets }
        return keyWindow?.safeAreaInsets ?? defaultInsets
    }()
    
    static let isFringeScreen: Bool = safeAreaInsets.bottom > 0
    
    static let appVersionStr: String = ((Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "" )
    static let appBundleStr: String = ((Bundle.main.infoDictionary?["CFBundleVersion"] as? String) ?? "" )
    static let appDisplayName: String = ((Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String) ?? "" )
    static let appBundleId: String = ((Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String) ?? "" )
    
    static let iosVersionStr: String = UIDevice.current.systemVersion
    
    static let cacheDir: String = (NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first) ?? ""
    static let tempDir: String = NSTemporaryDirectory()
    static let documentDir: String = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first) ?? ""
    
    static var appIconName: String? {
        
        let bundleIconsOrEmpty: [String: Any]? = Bundle.main.object(forInfoDictionaryKey: "CFBundleIcons") as? [String: Any]
        guard let bundleIcons = bundleIconsOrEmpty else { return nil }
        
        let primaryIconOrEmpty = bundleIcons["CFBundlePrimaryIcon"] as? [String: Any]
        guard let primaryIcon = primaryIconOrEmpty else { return nil }
        
        let iconFilesOrEmpty = primaryIcon["CFBundleIconFiles"] as? [String]
        guard let iconFiles = iconFilesOrEmpty else { return nil }
        
        return iconFiles.last
        
    }
    
    static func jumpToSystemPrivacySettings() {
        
        guard let appSetting = URL(string: UIApplication.openSettingsURLString) else { return }
        
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(appSetting, options: [:], completionHandler: nil)
        } else {
            UIApplication.shared.openURL(appSetting)
        }
        
    }
    
    //    // webview缓存
    //     static func webviewCacheSize() -> UInt {
    //
    //    }
    
    // 0 .. 100
    static var screenBrightness: Int {
#if os(iOS)
        return Int(screen.brightness * 100)
#else
        return 100
#endif
    }
    
}
